package btree;

import global.AttrType;
import global.GlobalConst;
import global.PageId;
import global.RID;
import global.SystemDefs;

import java.io.IOException;


import bufmgr.*;



import diskmgr.Page;
import exceptions.*;

public class Print implements GlobalConst{
	  public static void printBTree(BTreeHeaderPage header) 
			    throws IOException, 
				   ConstructPageException, 
				   IteratorException,
				   HashEntryNotFoundException,
				   InvalidFrameNumberException,
				   PageUnpinnedException,
				   ReplacerException 
			    {
			      if(header.getRoot().pid == INVALID_PAGE) {
				System.out.println("The Tree is Empty!!!");
				return;
			      }
			      
			      System.out.println("");
			      System.out.println("");
			      System.out.println("");
			      System.out.println("---------------The B+ Tree Structure---------------");
			      
			      
			      System.out.println(1+ "     "+header.getRoot());
			      
			      _printTree(header.getRoot(), "     ", 1, header.getKeyType());
			      
			      System.out.println("--------------- End ---------------");
			      System.out.println("");
			      System.out.println("");
			    }
			  
			  private static void _printTree(PageId currentPageId, String prefix, int i, 
							 int keyType) 
			    throws IOException, 
				   ConstructPageException, 
				   IteratorException,
				   HashEntryNotFoundException,
				   InvalidFrameNumberException,
				   PageUnpinnedException,
				   ReplacerException 
			    {
			      
			      BTSortedPage sortedPage=new BTSortedPage(currentPageId, keyType);
			      prefix=prefix+"       ";
			      i++;
			      if( sortedPage.getType()==NodeType.INDEX) {  
				BTIndexPage indexPage=new BTIndexPage((Page)sortedPage, keyType);
				
				System.out.println(i+prefix+ indexPage.getPrevPage());
				_printTree( indexPage.getPrevPage(), prefix, i, keyType);
				
				RID rid=new RID();
				for( KeyDataEntry entry=indexPage.getFirst(rid); entry!=null; 
				     entry=indexPage.getNext(rid)) {
				  System.out.println(i+prefix+(IndexData)entry.data);
				  _printTree( ((IndexData)entry.data).getData(), prefix, i, keyType);
				}
			      }
			      SystemDefs.JavabaseBM.unpinPage(currentPageId , true/*dirty*/);
			    }
			  
			  
			  
			  /** For debug. Print all leaf pages of the B+ tree  out
			   *@param header  the head page of the B+ tree file
			   *@exception IOException  error from the lower layer
			   *@exception ConstructPageException error for BT page constructor
			   *@exception IteratorException  error from iterator
			   *@exception HashEntryNotFoundException  error from lower layer
			   *@exception InvalidFrameNumberException  error from lower layer
			   *@exception PageUnpinnedException  error from lower layer
			   *@exception ReplacerException  error from lower layer
			   */
			  public static void printAllLeafPages(BTreeHeaderPage header) 
			    throws IOException, 
				   ConstructPageException, 
				   IteratorException,
				   HashEntryNotFoundException,
				   InvalidFrameNumberException,
				   PageUnpinnedException,
				   ReplacerException 
			    {
				  
			      if(header.getRoot().pid == INVALID_PAGE) {
				System.out.println("The Tree is Empty!!!");
				return;
			      }
			      
			      System.out.println("");
			      System.out.println("");
			      System.out.println("");
			      System.out.println("---------------The B+ Tree Leaf Pages---------------");
			      
			      
			      _printAllLeafPages(header.getRoot(), header.getKeyType());
			      
			      System.out.println("");
			      System.out.println("");
			      System.out.println("------------- All Leaf Pages Have Been Printed --------");
			      System.out.println("");
			      System.out.println("");
			    }
			  
			  private static void _printAllLeafPages(PageId currentPageId,  int keyType) 
			    throws IOException, 
				   ConstructPageException, 
				   IteratorException,
				   InvalidFrameNumberException, 
				   HashEntryNotFoundException,
				   PageUnpinnedException,
				   ReplacerException
			    {
			      
			      BTSortedPage sortedPage=new BTSortedPage(currentPageId, keyType);
			      
			      if( sortedPage.getType()==NodeType.INDEX) {  
				BTIndexPage indexPage=new BTIndexPage((Page)sortedPage, keyType);
				
				_printAllLeafPages( indexPage.getPrevPage(),  keyType);
				
				RID rid=new RID();
				for( KeyDataEntry entry=indexPage.getFirst(rid); entry!=null; 
				     entry=indexPage.getNext(rid)) {
				  _printAllLeafPages( ((IndexData)entry.data).getData(),  keyType);
				}
			      }
			      
			      if( sortedPage.getType()==NodeType.LEAF) {  
				printPage(currentPageId, keyType);
			      }
			      
			      
			      SystemDefs.JavabaseBM.unpinPage(currentPageId , true/*dirty*/);
			    }
			  public static void printPage(PageId pageno, int keyType)
					    throws  IOException, 
						    IteratorException, 
						    ConstructPageException,
					            HashEntryNotFoundException, 
						    ReplacerException, 
						    PageUnpinnedException, 
					            InvalidFrameNumberException
					    {
					      BTSortedPage sortedPage=new BTSortedPage(pageno, keyType);
					      int i;
					      i=0;
					      if ( sortedPage.getType()==NodeType.INDEX ) {
					        BTIndexPage indexPage=new BTIndexPage((Page)sortedPage, keyType);
					        System.out.println("");
					        System.out.println("**************To Print an Index Page ********");
					        System.out.println("Current Page ID: "+ indexPage.getCurPage().pid);
					        System.out.println("Left Link      : "+ indexPage.getLeftLink().pid);
						
					        RID rid=new RID();
						
					        for(KeyDataEntry entry=indexPage.getFirst(rid); entry!=null; 
						    entry=indexPage.getNext(rid)){
						  if( keyType==AttrType.attrInteger) 
						    System.out.println(i+" (key, pageId):   ("+ 
								       (IntegerKey)entry.key + ",  "+(IndexData)entry.data+ " )");
						  if( keyType==AttrType.attrString) 
						    System.out.println(i+" (key, pageId):   ("+ 
								       (StringKey)entry.key + ",  "+(IndexData)entry.data+ " )");
						  
						  i++;    
					        }
						
					        System.out.println("************** END ********");
					        System.out.println("");
					      }
					      else if ( sortedPage.getType()==NodeType.LEAF ) {
					        BTLeafPage leafPage=new BTLeafPage((Page)sortedPage, keyType);
					        System.out.println("");
					        System.out.println("**************To Print an Leaf Page ********");
					        System.out.println("Current Page ID: "+ leafPage.getCurPage().pid);
					        System.out.println("Left Link      : "+ leafPage.getPrevPage().pid);
					        System.out.println("Right Link     : "+ leafPage.getNextPage().pid);
						
					        RID rid=new RID();
						
					        for(KeyDataEntry entry=leafPage.getFirst(rid); entry!=null; 
						    entry=leafPage.getNext(rid)){
						  if( keyType==AttrType.attrInteger) 
						    System.out.println(i+" (key, [pageNo, slotNo]):   ("+ 
								       (IntegerKey)entry.key+ ",  "+(LeafData)entry.data+ " )");
						  if( keyType==AttrType.attrString) 
						    System.out.println(i+" (key, [pageNo, slotNo]):   ("+ 
								       (StringKey)entry.key + ",  "+(LeafData)entry.data); 
						  
						  i++;
					        }
						
						System.out.println("************** END ********");
						System.out.println("");
					      }
					      else {
						System.out.println("Sorry!!! This page is neither Index nor Leaf page.");
					      }      
					      
					      SystemDefs.JavabaseBM.unpinPage(pageno, true/*dirty*/);
					    }
					  
}
